use pest::Parser;
use pest_derive::Parser;

#[derive(Parser)]
#[grammar = "lexer.pest"] // 指向你的 .pest 文件
struct ExpressionParser;

#[derive(Debug, PartialEq)]
pub enum Token {
    Keywords(String),
    Operators(String),
    Symbols(String),
    Ident(String),
    IntegerConst(String),
}

impl Token {
    pub fn get_type_name(&self) -> &str {
        match self {
            Token::Keywords(s) => match s.as_str() {
                "const" => "CONST",
                "int" => "INT",
                "void" => "VOID",
                "if" => "IF",
                "else" => "ELSE",
                "while" => "WHILE",
                "break" => "BREAK",
                "continue" => "CONTINUE",
                "return" => "RETURN",
                _ => "KEYWORDS",
            },
            Token::Operators(s) => match s.as_str() {
                "+" => "PLUS",
                "-" => "MINUS",
                "*" => "MUL",
                "/" => "DIV",
                "%" => "MOD",
                "=" => "ASSIGN",
                "==" => "EQ",
                "!=" => "NEQ",
                "<" => "LT",
                ">" => "GT",
                "<=" => "LE",
                ">=" => "GE",
                "!" => "NOT",
                "&&" => "AND",
                "||" => "OR",
                _ => "OPERATORS",
            },
            Token::Symbols(s) => match s.as_str() {
                "(" => "L_PAREN",
                ")" => "R_PAREN",
                "{" => "L_BRACE",
                "}" => "R_BRACE",
                "[" => "L_BRACKT",
                "]" => "R_BRACKT",
                "," => "COMMA",
                ";" => "SEMICOLON",
                _ => "SYMBOLS",
            },
            Token::Ident(_) => "IDENT",
            Token::IntegerConst(_) => "INTEGER_CONST",
        }
    }

    pub fn get_text(&self) -> String {
        match self {
            Token::Keywords(s) | Token::Operators(s) | Token::Symbols(s) => s.clone(),
            Token::Ident(s) => s.trim().to_string(),
            Token::IntegerConst(s) => {
                // 转换十六进制和八进制为十进制
                if s.starts_with("0x") || s.starts_with("0X") {
                    // 十六进制
                    if let Ok(val) = i64::from_str_radix(&s[2..], 16) {
                        val.to_string()
                    } else {
                        s.clone()
                    }
                } else if s.starts_with("0") && s.len() > 1 && s.chars().all(|c| c.is_ascii_digit())
                {
                    // 八进制 (以0开头且全是数字)
                    if let Ok(val) = i64::from_str_radix(s, 8) {
                        val.to_string()
                    } else {
                        s.clone()
                    }
                } else {
                    // 十进制
                    s.clone()
                }
            }
        }
    }
}

pub fn tokenize(unparsed_file: &str) -> Result<Vec<(Token, usize)>, String> {
    match ExpressionParser::parse(Rule::file, unparsed_file) {
        Ok(mut pairs) => {
            let pairs = pairs.next().unwrap();
            let tokens = pairs
                .into_inner()
                .filter_map(|pair| {
                    let line_no = pair.as_span().start_pos().line_col().0;
                    match pair.as_rule() {
                        Rule::keywords => Some((Token::Keywords(pair.as_str().into()), line_no)),
                        Rule::operators => Some((Token::Operators(pair.as_str().into()), line_no)),
                        Rule::symbols => Some((Token::Symbols(pair.as_str().into()), line_no)),
                        Rule::IDENT => Some((Token::Ident(pair.as_str().into()), line_no)),
                        Rule::INTEGER_CONST => {
                            Some((Token::IntegerConst(pair.as_str().into()), line_no))
                        }
                        Rule::EOI => None,
                        _ => None,
                    }
                })
                .collect();
            Ok(tokens)
        }
        Err(e) => {
            // 解析 pest 错误信息
            let error_msg = format!("{}", e);

            // 提取行号和字符信息
            if let Some(line_start) = error_msg.find("-->") {
                if let Some(line_end) = error_msg[line_start..].find(':') {
                    let line_part = &error_msg[line_start + 4..line_start + line_end];
                    if let Ok(line_no) = line_part.parse::<usize>() {
                        // 查找神秘字符
                        let lines: Vec<&str> = unparsed_file.lines().collect();
                        if line_no > 0 && line_no <= lines.len() {
                            let line_content = lines[line_no - 1];
                            // 寻找不认识的字符
                            for ch in line_content.chars() {
                                if !ch.is_alphanumeric()
                                    && !ch.is_whitespace()
                                    && !"(){}[];,+-*/%=!<>&|".contains(ch)
                                {
                                    return Err(format!(
                                        "Error type A at Line {}: Mysterious character \"{}\".",
                                        line_no, ch
                                    ));
                                }
                            }
                        }
                    }
                }
            }

            Err(format!("Parse error: {}", e))
        }
    }
}
